package cn.getech.data.metadata.model.excel;

import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.utils.BaseRes;
import cn.getech.data.intelligence.common.validator.ValidatorUtils;
import cn.getech.data.metadata.constant.TaskStatusEnum;
import cn.getech.data.metadata.entity.meta.CollectionTask;
import cn.getech.data.metadata.service.CollectionTaskService;
import cn.getech.data.metadata.utils.MapUtils;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class TableFieldListener extends AnalysisEventListener<CollectionTableFieldExcel> {

    /**
     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    private List<CollectionTableFieldExcel> list = new ArrayList<>();
    private CollectionTaskService collectionTaskService;
    private Long taskId;
    private Long start;//记录开始时间
    private Boolean check = false;
    private JSONObject data = new JSONObject();
    private List<ExcelError> errorList = Lists.newArrayList();

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        Field[] fields = CollectionTableFieldExcel.class.getDeclaredFields();
        for (Integer integer : headMap.keySet()) {
            Field field = fields[integer];
            ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
            if (excelProperty != null) {
                if (!excelProperty.value()[0].equals(headMap.get(integer).trim())) {
                    log.info("name1:{},name2:{}",excelProperty.value()[0],headMap.get(integer));
                    throw new RRException("excel模板内容格式错误");
                }
            }
        }
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws RRException {
        ReadRowHolder readRowHolder = context.readRowHolder();
        Integer rowIndex = readRowHolder.getRowIndex();
        if(exception instanceof ExcelDataConvertException){
            ExcelDataConvertException e= (ExcelDataConvertException) exception;
            ExcelError errorDTO = new ExcelError();
            errorDTO.setHeadName(String.join(",",e.getExcelContentProperty().getHead().getHeadNameList()));
            errorDTO.setColumnIndex(e.getColumnIndex() + 1);
            errorDTO.setRowIndex(e.getRowIndex() + 1);
            errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + " 行第" + errorDTO.getColumnIndex() + "列," + "数据类型错误");
            errorDTO.setValue(e.getCellData().getStringValue());
            log.warn("rowIndex  {} \n msg:{}",rowIndex,JSONObject.toJSONString(errorDTO));
            errorList.add(errorDTO);
        }else if (exception instanceof RRException){
            throw new RRException(((RRException) exception).getMsg());
        }
    }
    public TableFieldListener(Long taskId, CollectionTaskService collectionTaskService) {
        this.start = System.currentTimeMillis();
        this.taskId = taskId;
        this.collectionTaskService = collectionTaskService;
    }

    public TableFieldListener(Long taskId, CollectionTaskService collectionTaskService, Boolean check) {
        this.start = System.currentTimeMillis();
        this.taskId = taskId;
        this.collectionTaskService = collectionTaskService;
        this.check = check;
    }

    @Override
    public void invoke(CollectionTableFieldExcel data, AnalysisContext analysisContext) {
        if (check) {
            ReadRowHolder readRowHolder = analysisContext.readRowHolder();
            Integer rowIndex = readRowHolder.getRowIndex();
            ExcelError errorDTO = new ExcelError();
            errorDTO.setRowIndex(rowIndex + 1);
            try {
                ValidatorUtils.validateEntity(data);
                String errorField = data.validateValue();
                if (StringUtils.isNotEmpty(errorField)) {
                    errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + "行,"+errorField+",取值范围错误");
                    errorList.add(errorDTO);
                } else {
                    list.add(data);
                }
            } catch (RRException e) {
                errorDTO.setErrMsg("第" + errorDTO.getRowIndex() + "行," + e.getMsg());
                errorList.add(errorDTO);
            }
        } else {
            data.setOrder(list.size() + 1);
            list.add(data);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (check) {
            data = collectionTaskService.getCheckExcel(taskId, list);
        } else {
            // 这里也要保存数据，确保最后遗留的数据也存储到数据库
            CollectionTask task = collectionTaskService.getById(taskId);
            if (task != null) {
                try {
                    Long userId = ShiroUtils.getUserId();
                    task.setRunTime(new Date());
                    task.setTaskRunLeader(userId);
                    task.setRunStatus(TaskStatusEnum.RUNNING.getValue());
                    collectionTaskService.updateById(task);
                    collectionTaskService.saveTableField(start, taskId, list, check);
                } catch (Exception e) {
                    task.setRunStatus(TaskStatusEnum.FAIL.getValue());
                    task.setRunCount(task.getRunCount() + 1);
                    collectionTaskService.updateById(task);
                    collectionTaskService.insertRunLog(start, task, MapUtils.getExceptionInfo(e));
                    log.error("导入失败:",e);
                    data.put("error_log","导入失败");
                }
            }else{
                throw new RRException("任务不存在");
            }
        }
    }

    public BaseRes getCheckExcel() {
        if (data != null) {
            Map<String, List<CollectionTableFieldExcel>> mapList = list.stream()
                    .collect(Collectors.groupingBy(CollectionTableFieldExcel::getUniqueTable));
            if (data.getJSONArray("fieldAddList") != null) {
                for (String tableDb : mapList.keySet()) {
                    List<CollectionTableFieldExcel> fieldList = mapList.get(tableDb);
                    Set<String> fieldSet = fieldList.stream().map(CollectionTableFieldExcel::getFieldName)
                            .collect(Collectors.toSet());
                    if (fieldList.size() != fieldSet.size()) {
                        data.put("error_log", tableDb+"中存在重复字段");
                    }
                }
            }
           //data.put("errorList", errorList);
            if (CollectionUtil.isNotEmpty(errorList)) {
                List<String> msg = errorList.stream()
                        .map(ExcelError::getErrMsg).collect(Collectors.toList());
                data.put("error_log", String.join("\n", msg));
            }else if (CollectionUtil.isEmpty(list)) {
                data.put("error_log", "文件内容为空");
            }
        }
        return BaseRes.okWithData(data);
    }

    public JSONObject getData() {
        return data;
    }
}
